package com.baiku.sanhos.filter;

import com.alibaba.fastjson.JSONObject;
import com.baiku.sanhos.domain.LoginUser;
import com.baiku.sanhos.pojo.po.UserLoginInfoPO;
import com.baiku.sanhos.utils.JWTEasyUtil;
import com.baiku.sanhos.utils.RedisCache;
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired JWTEasyUtil jwtEasyUtil;

    @Autowired
    RedisCache redisCache;
    @Autowired
    StringRedisTemplate redisTemplate;

    private static final String REDIS_LONGIN_PRE = "login:";
    private static final String REDIS_LONGIN_TOKEN = "login:token:";



    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 获取JWT
        String token = request.getHeader("token");





        if(StringUtils.isEmpty(token)){

            filterChain.doFilter(request, response);
            return;
        }
        //从Redis中读取此JWT的数据

        UserLoginInfoPO loginInfo = redisCache.getLoginInfo(token);
        //判断Redis中是否存在此JWT相关数据
        if(loginInfo==null){
            //放行，相当于没有携带JWT（Redis里没有对应的数据）
            filterChain.doFilter(request,response);
            return;
        }
        // 判断此次请求，与当初登录成功时的相关信息是否相同
        String userAgent = loginInfo.getUserAgent();




        String ip = loginInfo.getIp();
        if (!userAgent.equals(request.getHeader("User-Agent"))
                && !ip.equals(request.getRemoteAddr())) {
            // 本次请求的信息与当初登录时完全不同，则视为无效的JWT

            filterChain.doFilter(request, response);
            return;
        }

        String userId = null;
        // 解析JWT
        try {
            Claims parseToken = jwtEasyUtil.parseToken(token);
            userId = parseToken.getSubject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 首先判断JWT值过期没 判断redis缓存里面有没有LoginUser登录信息
        String redisToken1 = redisTemplate.opsForValue().get(REDIS_LONGIN_TOKEN + userId);
      String redisToken=redisToken1.trim().replace("\"","");
        if(StringUtils.isEmpty(redisToken) || (!redisToken.equals(token))){
            throw new AccountExpiredException("token过期，请重新登录");
        }


        // TODO 从redis中获取用户信息
        String userJson = redisTemplate.opsForValue().get(REDIS_LONGIN_PRE + userId);
        // 判断用户是否已经注销了
        if(Objects.isNull(userJson)){
            throw new AccountExpiredException("请重新登录");
            //throw new RuntimeException("请重新登录");
        }
        LoginUser loginUser = JSONObject.parseObject(userJson, LoginUser.class);
        // 存入SecurityContextHolder
        // TODO  获取权限信息封装到Authentication中
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}
